Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.130
diff -c -r2.130 catalogs.sgml
*** doc/src/sgml/catalogs.sgml	25 Aug 2006 04:06:44 -0000	2.130
--- doc/src/sgml/catalogs.sgml	30 Aug 2006 07:47:05 -0000
***************
*** 3513,3518 ****
--- 3513,3531 ----
       </row>
  
       <row>
+       <entry><structfield>ev_kind</structfield></entry>
+       <entry><type>char</type></entry>
+       <entry></entry>
+       <entry>  
+        <literal>l</> = with local check option,   
+        <literal>c</> = with cascaded check option,
+        <literal>n</> = no check option specified,
+        <literal>e</> = rule was created by user 
+        <literal>r</> = implicit DO INSTEAD NOTHING rule for check option
+       </entry>
+      </row>
+ 
+      <row>
        <entry><structfield>ev_qual</structfield></entry>
        <entry><type>text</type></entry>
        <entry></entry>
Index: doc/src/sgml/information_schema.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/information_schema.sgml,v
retrieving revision 1.26
diff -c -r1.26 information_schema.sgml
*** doc/src/sgml/information_schema.sgml	2 May 2006 18:07:51 -0000	1.26
--- doc/src/sgml/information_schema.sgml	30 Aug 2006 07:47:07 -0000
***************
*** 5085,5091 ****
       <row>
        <entry><literal>check_option</literal></entry>
        <entry><type>character_data</type></entry>
!       <entry>Applies to a feature not available in <productname>PostgreSQL</></entry>
       </row>
  
       <row>
--- 5085,5095 ----
       <row>
        <entry><literal>check_option</literal></entry>
        <entry><type>character_data</type></entry>
!       <entry>
!        The level of integrity checking in updatable views,
!        either <literal>LOCAL</literal>, <literal>CASCADED</literal>
!        or <literal>NONE</literal>
!      </entry>
       </row>
  
       <row>
Index: doc/src/sgml/intro.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/intro.sgml,v
retrieving revision 1.31
diff -c -r1.31 intro.sgml
*** doc/src/sgml/intro.sgml	10 Mar 2006 19:10:48 -0000	1.31
--- doc/src/sgml/intro.sgml	30 Aug 2006 07:47:07 -0000
***************
*** 110,116 ****
       <simpara>triggers</simpara>
      </listitem>
      <listitem>
!      <simpara>views</simpara>
      </listitem>
      <listitem>
       <simpara>transactional integrity</simpara>
--- 110,116 ----
       <simpara>triggers</simpara>
      </listitem>
      <listitem>
!      <simpara>updatable views</simpara>
      </listitem>
      <listitem>
       <simpara>transactional integrity</simpara>
Index: doc/src/sgml/ref/create_view.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/create_view.sgml,v
retrieving revision 1.31
diff -c -r1.31 create_view.sgml
*** doc/src/sgml/ref/create_view.sgml	1 Nov 2005 21:09:50 -0000	1.31
--- doc/src/sgml/ref/create_view.sgml	30 Aug 2006 07:47:08 -0000
***************
*** 22,27 ****
--- 22,28 ----
  <synopsis>
  CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] VIEW <replaceable class="PARAMETER">name</replaceable> [ ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) ]
      AS <replaceable class="PARAMETER">query</replaceable>
+     [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 109,114 ****
--- 110,150 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <variablelist>
+      <varlistentry>
+       <term><literal>CHECK OPTION</literal></term>
+       <listitem>
+        <para>
+         This option has to do with updatable views.  All
+         <command>INSERT</> and <command>UPDATE</> commands on the view
+         will be checked to ensure data satisfy the view-defining
+         condition (that is, the new data would be visible through the
+         view).  If they do not, the update will be rejected.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term><literal>LOCAL</literal></term>
+       <listitem>
+        <para>
+         Check for integrity on this view.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term><literal>CASCADED</literal></term>
+       <listitem>
+        <para>
+         Check for integrity on this view and on any dependent
+         view.  <literal>CASCADED</> is assumed if neither
+         <literal>CASCADED</> nor <literal>LOCAL</> is specified.
+        </para>
+       </listitem>
+      </varlistentry>
+    
    </variablelist>
   </refsect1>
  
***************
*** 116,126 ****
    <title>Notes</title>
  
     <para>
!     Currently, views are read only: the system will not allow an insert,
!     update, or delete on a view.  You can get the effect of an updatable
!     view by creating rules that rewrite inserts, etc. on the view into
!     appropriate actions on other tables.  For more information see
!     <xref linkend="sql-createrule" endterm="sql-createrule-title">.
     </para>
  
     <para>
--- 152,201 ----
    <title>Notes</title>
  
     <para>
!     Currently, views are updatable following SQL92 specifications, that
!     is: 
!    </para>
! 
!    <itemizedlist>
!     <listitem>
!      <para>
!       Views with just one base table (or another updatable view)
!      </para>
!     </listitem>
! 
!     <listitem>
!      <para>No aggregate functions</para>
!     </listitem>
! 
!     <listitem>
!      <para>
!       No <literal>HAVING</literal>, <literal>DISTINCT</literal> nor
!       <literal>GROUP BY</literal> clauses
!      </para>
!     </listitem>
! 
!     <listitem>
!      <para>
!       No <literal>UNION</literal>, <literal>INTERSECT</literal>,
!       <literal>EXCEPT</literal>clauses
!      </para>
!     </listitem>
!    </itemizedlist>
! 
!    <para>
!     Views are insertable only if you provide in the defining
!     <command>SELECT</command> statement all columns that are NOT NULL and don't
!     have a default value.
!    </para>
! 
!    <para>
!     The updatable views implementation is based on the rule system.  Because of
!     this, you can get the same effect in more complex views by creating your
!     own rules that rewrite the <command>INSERT</command>,
!     <command>UPDATE</command> and <command>UPDATE</command> actions on the view
!     into appropriate actions on other tables. You can also replace
!     automatically generated rules with your own rules. For more information,
!     refer to <xref linkend="sql-createrule" endterm="sql-createrule-title">.
     </para>
  
     <para>
***************
*** 171,225 ****
    <title>Compatibility</title>
  
    <para>
-    The SQL standard specifies some additional capabilities for the
-    <command>CREATE VIEW</command> statement:
- <synopsis>
- CREATE VIEW <replaceable class="parameter">name</replaceable> [ ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ]
-     AS <replaceable class="PARAMETER">query</replaceable>
-     [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
- </synopsis>
-   </para>
- 
-   <para>
-    The optional clauses for the full SQL command are:
- 
-    <variablelist>
-      <varlistentry>
-       <term><literal>CHECK OPTION</literal></term>
-       <listitem>
-        <para>
-         This option has to do with updatable views.  All
-         <command>INSERT</> and <command>UPDATE</> commands on the view
-         will be checked to ensure data satisfy the view-defining
-         condition (that is, the new data would be visible through the
-         view). If they do not, the update will be rejected.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry>
-       <term><literal>LOCAL</literal></term>
-       <listitem>
-        <para>
-         Check for integrity on this view.
-        </para>
-       </listitem>
-      </varlistentry>
- 
-      <varlistentry>
-       <term><literal>CASCADED</literal></term>
-       <listitem>
-        <para>
-         Check for integrity on this view and on any dependent
-         view. <literal>CASCADED</> is assumed if neither
-         <literal>CASCADED</> nor <literal>LOCAL</> is specified.
-        </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-   </para>
- 
-   <para>
     <command>CREATE OR REPLACE VIEW</command> is a
     <productname>PostgreSQL</productname> language extension.
     So is the concept of a temporary view.
--- 246,251 ----
Index: src/backend/catalog/information_schema.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/information_schema.sql,v
retrieving revision 1.33
diff -c -r1.33 information_schema.sql
*** src/backend/catalog/information_schema.sql	2 Apr 2006 17:38:13 -0000	1.33
--- src/backend/catalog/information_schema.sql	30 Aug 2006 07:47:10 -0000
***************
*** 2126,2132 ****
                    ELSE null END
               AS character_data) AS view_definition,
  
!            CAST('NONE' AS character_data) AS check_option,
  
             CAST(
               CASE WHEN EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 2 AND is_instead)
--- 2126,2143 ----
                    ELSE null END
               AS character_data) AS view_definition,
  
!            CAST(
!              CASE WHEN EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 2 AND is_instead AND ev_kind = 'l')
!                     OR EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 3 AND is_instead AND ev_kind = 'l')
!                     OR EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 4 AND is_instead AND ev_kind = 'l')
!                   THEN 'LOCAL'
!                   WHEN EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 2 AND is_instead AND ev_kind = 'c')
!                     OR EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 3 AND is_instead AND ev_kind = 'c')
!                     OR EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 4 AND is_instead AND ev_kind = 'c')
!                   THEN 'CASCADED'
!                   ELSE 'NONE' 
!              END
!            AS character_data) AS check_option,
  
             CAST(
               CASE WHEN EXISTS (SELECT 1 FROM pg_rewrite WHERE ev_class = c.oid AND ev_type = 2 AND is_instead)
Index: src/backend/commands/view.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/view.c,v
retrieving revision 1.97
diff -c -r1.97 view.c
*** src/backend/commands/view.c	21 Aug 2006 00:57:24 -0000	1.97
--- src/backend/commands/view.c	30 Aug 2006 07:47:12 -0000
***************
*** 29,41 ****
--- 29,44 ----
  #include "rewrite/rewriteDefine.h"
  #include "rewrite/rewriteManip.h"
  #include "rewrite/rewriteSupport.h"
+ #include "rewrite/viewUpdate.h"
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
+ #include "utils/memutils.h"
  
  
  static void checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc);
  static bool isViewOnTempTable_walker(Node *node, void *context);
  
+ 
  /*---------------------------------------------------------------------
   * isViewOnTempTable
   *
***************
*** 280,329 ****
  }
  
  static void
! DefineViewRules(const RangeVar *view, Query *viewParse, bool replace)
  {
  	RuleStmt   *retrieve_rule;
  
- #ifdef NOTYET
- 	RuleStmt   *replace_rule;
- 	RuleStmt   *append_rule;
- 	RuleStmt   *delete_rule;
- #endif
- 
  	retrieve_rule = FormViewRetrieveRule(view, viewParse, replace);
  
! #ifdef NOTYET
! 	replace_rule = FormViewReplaceRule(view, viewParse);
! 	append_rule = FormViewAppendRule(view, viewParse);
! 	delete_rule = FormViewDeleteRule(view, viewParse);
! #endif
! 
! 	DefineQueryRewrite(retrieve_rule);
! 
! #ifdef NOTYET
! 	DefineQueryRewrite(replace_rule);
! 	DefineQueryRewrite(append_rule);
! 	DefineQueryRewrite(delete_rule);
! #endif
  
  }
  
! /*---------------------------------------------------------------
   * UpdateRangeTableOfViewParse
   *
!  * Update the range table of the given parsetree.
!  * This update consists of adding two new entries IN THE BEGINNING
!  * of the range table (otherwise the rule system will die a slow,
!  * horrible and painful death, and we do not want that now, do we?)
!  * one for the OLD relation and one for the NEW one (both of
   * them refer in fact to the "view" relation).
   *
!  * Of course we must also increase the 'varnos' of all the Var nodes
!  * by 2...
   *
!  * These extra RT entries are not actually used in the query,
!  * except for run-time permission checking.
!  *---------------------------------------------------------------
   */
  static Query *
  UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
--- 283,314 ----
  }
  
  static void
! DefineViewRules(const RangeVar *view, Query *viewParse, bool replace,
! 				bool checkOption, bool cascade)
  {
  	RuleStmt   *retrieve_rule;
  
  	retrieve_rule = FormViewRetrieveRule(view, viewParse, replace);
  
! 	DefineQueryRewrite(retrieve_rule, 
! 					   makeViewCheckOption(checkOption, cascade));
  
+ 	CreateViewUpdateRules(viewParse, view, checkOption, cascade);
  }
  
! /*
   * UpdateRangeTableOfViewParse
   *
!  * Update the range table of the given parsetree.  This update consists of
!  * adding two new entries IN THE BEGINNING of the range table (otherwise the
!  * rule system will die a slow, horrible and painful death, and we do not want
!  * that now, do we?) one for the OLD relation and one for the NEW one (both of
   * them refer in fact to the "view" relation).
   *
!  * Of course we must also increase the 'varnos' of all the Var nodes by 2...
   *
!  * These extra RT entries are not actually used in the query, except for
!  * run-time permission checking.
   */
  static Query *
  UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
***************
*** 387,393 ****
   *-------------------------------------------------------------------
   */
  void
! DefineView(RangeVar *view, Query *viewParse, bool replace)
  {
  	Oid			viewOid;
  
--- 372,379 ----
   *-------------------------------------------------------------------
   */
  void
! DefineView(RangeVar *view, Query *viewParse, bool replace, bool checkOption,
! 		   bool cascade)
  {
  	Oid			viewOid;
  
***************
*** 428,434 ****
  	/*
  	 * Now create the rules associated with the view.
  	 */
! 	DefineViewRules(view, viewParse, replace);
  }
  
  /*
--- 414,420 ----
  	/*
  	 * Now create the rules associated with the view.
  	 */
! 	DefineViewRules(view, viewParse, replace, checkOption, cascade);
  }
  
  /*
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.558
diff -c -r2.558 gram.y
*** src/backend/parser/gram.y	25 Aug 2006 04:06:51 -0000	2.558
--- src/backend/parser/gram.y	30 Aug 2006 07:47:28 -0000
***************
*** 4494,4500 ****
   *****************************************************************************/
  
  RuleStmt:	CREATE opt_or_replace RULE name AS
! 			{ QueryIsRule=TRUE; }
  			ON event TO qualified_name where_clause
  			DO opt_instead RuleActionList
  				{
--- 4494,4500 ----
   *****************************************************************************/
  
  RuleStmt:	CREATE opt_or_replace RULE name AS
! 			{ QueryIsRule = true; }
  			ON event TO qualified_name where_clause
  			DO opt_instead RuleActionList
  				{
***************
*** 4507,4513 ****
  					n->instead = $13;
  					n->actions = $14;
  					$$ = (Node *)n;
! 					QueryIsRule=FALSE;
  				}
  		;
  
--- 4507,4513 ----
  					n->instead = $13;
  					n->actions = $14;
  					$$ = (Node *)n;
! 					QueryIsRule = false;
  				}
  		;
  
***************
*** 4520,4532 ****
  /* the thrashing around here is to discard "empty" statements... */
  RuleActionMulti:
  			RuleActionMulti ';' RuleActionStmtOrEmpty
! 				{ if ($3 != NULL)
  					$$ = lappend($1, $3);
  				  else
  					$$ = $1;
  				}
  			| RuleActionStmtOrEmpty
! 				{ if ($1 != NULL)
  					$$ = list_make1($1);
  				  else
  					$$ = NIL;
--- 4520,4534 ----
  /* the thrashing around here is to discard "empty" statements... */
  RuleActionMulti:
  			RuleActionMulti ';' RuleActionStmtOrEmpty
! 				{
! 				  if ($3 != NULL)
  					$$ = lappend($1, $3);
  				  else
  					$$ = $1;
  				}
  			| RuleActionStmtOrEmpty
! 				{
! 				  if ($1 != NULL)
  					$$ = list_make1($1);
  				  else
  					$$ = NIL;
***************
*** 4791,4796 ****
--- 4793,4799 ----
  					n->view->istemp = $2;
  					n->aliases = $5;
  					n->query = (Query *) $7;
+ 					n->options = $8;
  					$$ = (Node *) n;
  				}
  		| CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list
***************
*** 4802,4807 ****
--- 4805,4811 ----
  					n->view->istemp = $4;
  					n->aliases = $7;
  					n->query = (Query *) $9;
+ 					n->options = $10;
  					$$ = (Node *) n;
  				}
  		;
***************
*** 4813,4833 ****
  opt_check_option:
  		WITH_CHECK OPTION
  				{
! 					ereport(ERROR,
! 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 							 errmsg("WITH CHECK OPTION is not implemented")));
  				}
  		| WITH_CASCADED CHECK OPTION
  				{
! 					ereport(ERROR,
! 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 							 errmsg("WITH CHECK OPTION is not implemented")));
  				}
  		| WITH_LOCAL CHECK OPTION
  				{
! 					ereport(ERROR,
! 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 							 errmsg("WITH CHECK OPTION is not implemented")));
  				}
  		| /* EMPTY */							{ $$ = NIL; }
  		;
--- 4817,4831 ----
  opt_check_option:
  		WITH_CHECK OPTION
  				{
! 					$$ = list_make1((Node *)makeString("cascaded"));
  				}
  		| WITH_CASCADED CHECK OPTION
  				{
! 					$$ = list_make1((Node *)makeString("cascaded"));
  				}
  		| WITH_LOCAL CHECK OPTION
  				{
! 					$$ = list_make1((Node *)makeString("local"));
  				}
  		| /* EMPTY */							{ $$ = NIL; }
  		;
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.176
diff -c -r1.176 keywords.c
*** src/backend/parser/keywords.c	25 Aug 2006 04:06:52 -0000	1.176
--- src/backend/parser/keywords.c	30 Aug 2006 07:47:31 -0000
***************
*** 67,72 ****
--- 67,73 ----
  	{"cache", CACHE},
  	{"called", CALLED},
  	{"cascade", CASCADE},
+ 	{"cascaded", CASCADED},
  	{"case", CASE},
  	{"cast", CAST},
  	{"chain", CHAIN},
Index: src/backend/rewrite/Makefile
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/rewrite/Makefile,v
retrieving revision 1.15
diff -c -r1.15 Makefile
*** src/backend/rewrite/Makefile	29 Nov 2003 19:51:55 -0000	1.15
--- src/backend/rewrite/Makefile	30 Aug 2006 07:47:31 -0000
***************
*** 13,19 ****
  include $(top_builddir)/src/Makefile.global
  
  OBJS = rewriteRemove.o rewriteDefine.o \
!        rewriteHandler.o rewriteManip.o rewriteSupport.o
  
  all: SUBSYS.o
  
--- 13,20 ----
  include $(top_builddir)/src/Makefile.global
  
  OBJS = rewriteRemove.o rewriteDefine.o \
!        rewriteHandler.o rewriteManip.o rewriteSupport.o \
!        viewUpdate.o
  
  all: SUBSYS.o
  
Index: src/backend/rewrite/rewriteDefine.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v
retrieving revision 1.112
diff -c -r1.112 rewriteDefine.c
*** src/backend/rewrite/rewriteDefine.c	12 Aug 2006 20:05:55 -0000	1.112
--- src/backend/rewrite/rewriteDefine.c	30 Aug 2006 07:47:32 -0000
***************
*** 23,28 ****
--- 23,29 ----
  #include "parser/parse_expr.h"
  #include "rewrite/rewriteDefine.h"
  #include "rewrite/rewriteManip.h"
+ #include "rewrite/rewriteRemove.h"
  #include "rewrite/rewriteSupport.h"
  #include "storage/smgr.h"
  #include "utils/acl.h"
***************
*** 44,58 ****
  static Oid
  InsertRule(char *rulname,
  		   int evtype,
! 		   Oid eventrel_oid,
  		   AttrNumber evslot_index,
  		   bool evinstead,
  		   Node *event_qual,
  		   List *action,
  		   bool replace)
  {
  	char	   *evqual = nodeToString(event_qual);
  	char	   *actiontree = nodeToString((Node *) action);
  	int			i;
  	Datum		values[Natts_pg_rewrite];
  	char		nulls[Natts_pg_rewrite];
--- 45,62 ----
  static Oid
  InsertRule(char *rulname,
  		   int evtype,
! 		   /*Oid eventrel_oid,*/
! 		   Relation event_relation,
  		   AttrNumber evslot_index,
  		   bool evinstead,
+ 		   char evkind,
  		   Node *event_qual,
  		   List *action,
  		   bool replace)
  {
  	char	   *evqual = nodeToString(event_qual);
  	char	   *actiontree = nodeToString((Node *) action);
+ 	Oid        eventrel_oid = RelationGetRelid(event_relation);
  	int			i;
  	Datum		values[Natts_pg_rewrite];
  	char		nulls[Natts_pg_rewrite];
***************
*** 78,83 ****
--- 82,88 ----
  	values[i++] = Int16GetDatum(evslot_index);	/* ev_attr */
  	values[i++] = CharGetDatum(evtype + '0');	/* ev_type */
  	values[i++] = BoolGetDatum(evinstead);		/* is_instead */
+ 	values[i++] = CharGetDatum(evkind);         /* ev_kind */
  	values[i++] = DirectFunctionCall1(textin, CStringGetDatum(evqual)); /* ev_qual */
  	values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree));		/* ev_action */
  
***************
*** 96,114 ****
  
  	if (HeapTupleIsValid(oldtup))
  	{
  		if (!replace)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_DUPLICATE_OBJECT),
! 					 errmsg("rule \"%s\" for relation \"%s\" already exists",
! 							rulname, get_rel_name(eventrel_oid))));
  
  		/*
  		 * When replacing, we don't need to replace every attribute
  		 */
  		MemSet(replaces, ' ', sizeof(replaces));
  		replaces[Anum_pg_rewrite_ev_attr - 1] = 'r';
  		replaces[Anum_pg_rewrite_ev_type - 1] = 'r';
  		replaces[Anum_pg_rewrite_is_instead - 1] = 'r';
  		replaces[Anum_pg_rewrite_ev_qual - 1] = 'r';
  		replaces[Anum_pg_rewrite_ev_action - 1] = 'r';
  
--- 101,160 ----
  
  	if (HeapTupleIsValid(oldtup))
  	{
+ 		char old_tup_is_implicit = evkind;
+ 		Datum dat;
+ 		bool isnull;
+ 
+ 		dat = heap_getattr(oldtup,
+ 						   Anum_pg_rewrite_ev_kind,
+ 						   RelationGetDescr(pg_rewrite_desc),
+ 						   &isnull);
+ 		
+ 		if (isnull) 
+ 			/* should not happen */
+ 			elog(ERROR, "got null field in ev_kind where not null expected");
+ 		
  		if (!replace)
! 		{
! 			/*
! 			 * If REPLACE was not used we still have to check if the
! 			 * rule is implicit: then we have to replace it anyways.
! 			 */
! 			
! 			old_tup_is_implicit = DatumGetChar(dat);
! 			
! 			if (old_tup_is_implicit == NO_OPTION_EXPLICIT)
! 			{
! 				ereport(ERROR,
! 						(errcode(ERRCODE_DUPLICATE_OBJECT),
! 						 errmsg("rule \"%s\" for relation \"%s\" already exists",
! 								rulname, get_rel_name(eventrel_oid))));
! 			}
! 		}
  
  		/*
+ 		 * If we are about to replace an implicit rule
+ 		 * with an user defined rule, we need to drop all
+ 		 * implicit rules on the same action (for implicit 
+ 		 * conditional rules we have DO INSTEAD NOTHING RULES
+ 		 * present and vice versa...). We have to be careful not
+ 		 * to drop the current rule we want to replace...
+ 		 */
+ 		if ((old_tup_is_implicit != NO_OPTION_EXPLICIT)
+ 			&& (evkind == NO_OPTION_EXPLICIT))
+ 		{
+ 			deleteImplicitRulesOnEvent(event_relation, evtype,
+ 									   HeapTupleGetOid(oldtup));
+ 		}
+ 		
+ 		/*
  		 * When replacing, we don't need to replace every attribute
  		 */
  		MemSet(replaces, ' ', sizeof(replaces));
  		replaces[Anum_pg_rewrite_ev_attr - 1] = 'r';
  		replaces[Anum_pg_rewrite_ev_type - 1] = 'r';
  		replaces[Anum_pg_rewrite_is_instead - 1] = 'r';
+ 		replaces[Anum_pg_rewrite_ev_kind - 1] = 'r';
  		replaces[Anum_pg_rewrite_ev_qual - 1] = 'r';
  		replaces[Anum_pg_rewrite_ev_action - 1] = 'r';
  
***************
*** 124,129 ****
--- 170,186 ----
  	}
  	else
  	{
+ 		/*
+ 		 * Implicit rules should be dropped automatically when someone
+ 		 * wants to have its *own* rules on the view. is_implicit is set
+ 		 * to NO_OPTION_EXPLICIT in this case so we drop all implicit 
+ 		 * rules on the specified event type immediately.
+ 		 */
+ 
+ 		if (evkind == NO_OPTION_EXPLICIT)
+ 			deleteImplicitRulesOnEvent(event_relation, evtype,
+ 									   InvalidOid);
+ 
  		tup = heap_formtuple(pg_rewrite_desc->rd_att, values, nulls);
  
  		rewriteObjectId = simple_heap_insert(pg_rewrite_desc, tup);
***************
*** 177,183 ****
  }
  
  void
! DefineQueryRewrite(RuleStmt *stmt)
  {
  	RangeVar   *event_obj = stmt->relation;
  	Node	   *event_qual = stmt->whereClause;
--- 234,240 ----
  }
  
  void
! DefineQueryRewrite(RuleStmt *stmt, char ev_kind)
  {
  	RangeVar   *event_obj = stmt->relation;
  	Node	   *event_qual = stmt->whereClause;
***************
*** 443,457 ****
  		setRuleCheckAsUser_Query(query, GetUserId());
  	}
  	setRuleCheckAsUser_Expr(event_qual, GetUserId());
! 
  	/* discard rule if it's null action and not INSTEAD; it's a no-op */
  	if (action != NIL || is_instead)
  	{
  		ruleId = InsertRule(stmt->rulename,
  							event_type,
! 							ev_relid,
  							event_attno,
  							is_instead,
  							event_qual,
  							action,
  							replace);
--- 500,515 ----
  		setRuleCheckAsUser_Query(query, GetUserId());
  	}
  	setRuleCheckAsUser_Expr(event_qual, GetUserId());
! 	
  	/* discard rule if it's null action and not INSTEAD; it's a no-op */
  	if (action != NIL || is_instead)
  	{
  		ruleId = InsertRule(stmt->rulename,
  							event_type,
! 							event_relation,
  							event_attno,
  							is_instead,
+ 							ev_kind,
  							event_qual,
  							action,
  							replace);
***************
*** 469,475 ****
  	}
  
  	/*
! 	 * IF the relation is becoming a view, delete the storage files associated
  	 * with it.  NB: we had better have AccessExclusiveLock to do this ...
  	 *
  	 * XXX what about getting rid of its TOAST table?  For now, we don't.
--- 527,533 ----
  	}
  
  	/*
! 	 * If the relation is becoming a view, delete the storage files associated
  	 * with it.  NB: we had better have AccessExclusiveLock to do this ...
  	 *
  	 * XXX what about getting rid of its TOAST table?  For now, we don't.
Index: src/backend/rewrite/rewriteHandler.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v
retrieving revision 1.165
diff -c -r1.165 rewriteHandler.c
*** src/backend/rewrite/rewriteHandler.c	2 Aug 2006 01:59:47 -0000	1.165
--- src/backend/rewrite/rewriteHandler.c	30 Aug 2006 07:47:34 -0000
***************
*** 15,20 ****
--- 15,21 ----
  
  #include "access/heapam.h"
  #include "catalog/pg_type.h"
+ #include "catalog/pg_rewrite.h"
  #include "nodes/makefuncs.h"
  #include "optimizer/clauses.h"
  #include "parser/analyze.h"
***************
*** 34,45 ****
  	CmdType		event;			/* type of rule being fired */
  } rewrite_event;
  
  static bool acquireLocksOnSubLinks(Node *node, void *context);
  static Query *rewriteRuleAction(Query *parsetree,
  				  Query *rule_action,
  				  Node *rule_qual,
  				  int rt_index,
! 				  CmdType event);
  static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
  static void rewriteTargetList(Query *parsetree, Relation target_relation,
  							  List **attrno_list);
--- 35,55 ----
  	CmdType		event;			/* type of rule being fired */
  } rewrite_event;
  
+ /* Rule rewrite status for updatable views */
+ typedef struct view_update_event
+ {
+ 	bool viewUpdate;
+ 	bool needCheckOption;
+ 	char checkMode;	
+ } view_update_event;
+ 
  static bool acquireLocksOnSubLinks(Node *node, void *context);
  static Query *rewriteRuleAction(Query *parsetree,
  				  Query *rule_action,
  				  Node *rule_qual,
  				  int rt_index,
!                   CmdType event,
! 				  view_update_event *view_event);
  static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
  static void rewriteTargetList(Query *parsetree, Relation target_relation,
  							  List **attrno_list);
***************
*** 257,263 ****
  				  Query *rule_action,
  				  Node *rule_qual,
  				  int rt_index,
! 				  CmdType event)
  {
  	int			current_varno,
  				new_varno;
--- 267,274 ----
  				  Query *rule_action,
  				  Node *rule_qual,
  				  int rt_index,
! 				  CmdType event,
! 				  view_update_event *view_event)
  {
  	int			current_varno,
  				new_varno;
***************
*** 387,393 ****
  	 * queries one w/rule_qual, one w/NOT rule_qual. Also add user query qual
  	 * onto rule action
  	 */
! 	AddQual(sub_action, rule_qual);
  
  	AddQual(sub_action, parsetree->jointree->quals);
  
--- 398,405 ----
  	 * queries one w/rule_qual, one w/NOT rule_qual. Also add user query qual
  	 * onto rule action
  	 */
! 	if (view_event->needCheckOption)
! 		AddQual(sub_action, rule_qual);
  
  	AddQual(sub_action, parsetree->jointree->quals);
  
***************
*** 820,825 ****
--- 832,850 ----
  		}
  	}
  
+ #if 0
+  	/*
+  	 * I will do this only in case of relkind == RELKIND_VIEW.
+  	 * This is the last attempt to get a value for expr before we
+  	 * consider that expr must be NULL.
+  	 */
+  	if (expr == NULL && rel->rd_rel->relkind == RELKIND_VIEW)
+  	{
+  		expr = (Node *)makeNode(SetToDefault);
+  		return expr;
+  	}
+ #endif
+ 
  	if (expr == NULL)
  	{
  		/*
***************
*** 1359,1367 ****
--- 1384,1400 ----
   *					(must be initialized to FALSE)
   *	*qual_product - filled with modified original query if any qualified
   *					INSTEAD rule is found (must be initialized to NULL)
+  *	view_event - Holds the current state of the rules recursion. This
+  *               is important especially for implicit view update rules
+  *               created by the system to apply rule conditions based
+  *               on a view's CHECK OPTION. view_event is expected to
+  *               to be initialized by QueryRewrite().
   * Return value:
   *	list of rule actions adjusted for use with this query
   *
+ 
+  *               
+  *
   * Qualified INSTEAD rules generate their action with the qualification
   * condition added.  They also generate a modified version of the original
   * query with the negated qualification added, so that it will run only for
***************
*** 1376,1381 ****
--- 1409,1415 ----
  		  int rt_index,
  		  CmdType event,
  		  List *locks,
+ 		  view_update_event *view_event,
  		  bool *instead_flag,
  		  Query **qual_product)
  {
***************
*** 1390,1400 ****
  		QuerySource qsrc;
  		ListCell   *r;
  
  		/* Determine correct QuerySource value for actions */
  		if (rule_lock->isInstead)
  		{
! 			if (event_qual != NULL)
! 				qsrc = QSRC_QUAL_INSTEAD_RULE;
  			else
  			{
  				qsrc = QSRC_INSTEAD_RULE;
--- 1424,1524 ----
  		QuerySource qsrc;
  		ListCell   *r;
  
+ 		/*
+ 		 * Apply information to the view_event structure and save the
+ 		 * current recursion state of fireRules(). We distinguish
+ 		 * implicit and explicit rules, the first one are created
+ 		 * by the system to implement updatable views. We need to know
+ 		 * about the check option applied to such an implicit rule and
+ 		 * the current "depth" of the recursion, e.g. LOCAL CHECK
+ 		 * OPTION should be applied only once for implicit rules in
+ 		 * a cascading view update recursion and explicit conditional
+ 		 * rules need to be applied always.
+ 		 *
+ 		 *
+ 		 * First check: look if this rule is an implicit view update rule. If
+ 		 * false, always apply any rule qualification.
+ 		 */
+ 		if (rule_lock->ev_kind == NO_OPTION_EXPLICIT)
+ 		{
+ 			view_event->viewUpdate = false;
+ 			view_event->needCheckOption = true;
+ 			view_event->checkMode = rule_lock->ev_kind;
+ 		}
+ 		
+ 		/*
+ 		 * Second check: Look if we are already in a view update or not.  If
+ 		 * true and the event check mode is set to LOCAL_OPTION_IMPLICIT in
+ 		 * conjunction with viewUpdate = true, we don't need to apply the check
+ 		 * option otherwise.
+ 		 */
+ 		else if (!view_event->viewUpdate &&
+ 				 ((rule_lock->ev_kind == LOCAL_OPTION_IMPLICIT) ||
+ 				  (rule_lock->ev_kind == CASCADED_OPTION_IMPLICIT)))
+ 				 
+ 		{
+ 			/* apply check option, but only once */
+ 			view_event->viewUpdate = true;
+ 			view_event->needCheckOption = true;
+ 			view_event->checkMode = rule_lock->ev_kind;
+ 		}
+ 
+ 		/*
+ 		 * Third check: Look if we are in a recursive view update in
+ 		 * conjunction with a CASCADED CHECK OPTION. If true, we always need to
+ 		 * apply any check options found.
+ 		 */
+ 		else if (view_event->viewUpdate &&
+ 				 (view_event->checkMode == CASCADED_OPTION_IMPLICIT) &&
+ 				 (rule_lock->ev_kind != NO_OPTION_EXPLICIT))
+ 		{
+ 			view_event->needCheckOption = true;
+ 		}
+ 
+ 		/*
+ 		 * 4th check: make sure we reset the view update event if we are in a
+ 		 * recursive view update and passed the first view already. If we had a
+ 		 * LOCAL CHECK OPTION, we have to make sure we don't fire any check
+ 		 * options anymore.
+ 		 */
+ 		else if (view_event->viewUpdate &&
+ 				 (view_event->checkMode == LOCAL_OPTION_IMPLICIT) &&
+ 				 (rule_lock->ev_kind != NO_OPTION_EXPLICIT))
+ 		{
+ 			view_event->needCheckOption = false;
+ 			/* force LOCAL check mode */
+ 			view_event->checkMode = LOCAL_OPTION_IMPLICIT;
+ 		}
+ 
  		/* Determine correct QuerySource value for actions */
  		if (rule_lock->isInstead)
  		{
! 			if (event_qual != NULL) 
! 			{				
! 				/*
! 				 * Check out wether we need to apply any
! 				 * rule qualification to a view update rule.
! 				 * We only bother on implicit rules that aren't
! 				 * marked with NO_OPTION_EXPLICIT
! 				 */
! 				if ((rule_lock->ev_kind != NO_OPTION_EXPLICIT)
! 					&& (view_event->viewUpdate))
! 				{
! 					if (view_event->needCheckOption)
! 					{
! 						qsrc = QSRC_QUAL_INSTEAD_RULE;
! 					}
! 					else
! 					{
! 						qsrc = QSRC_INSTEAD_RULE;
! 						*instead_flag = true;
! 					}
! 				} 
! 				else 
! 				{
! 					qsrc = QSRC_QUAL_INSTEAD_RULE;
! 				}
! 			}
  			else
  			{
  				qsrc = QSRC_INSTEAD_RULE;
***************
*** 1438,1444 ****
  				continue;
  
  			rule_action = rewriteRuleAction(parsetree, rule_action,
! 											event_qual, rt_index, event);
  
  			rule_action->querySource = qsrc;
  			rule_action->canSetTag = false;		/* might change later */
--- 1562,1569 ----
  				continue;
  
  			rule_action = rewriteRuleAction(parsetree, rule_action,
! 											event_qual, rt_index, event,
! 											view_event);
  
  			rule_action->querySource = qsrc;
  			rule_action->canSetTag = false;		/* might change later */
***************
*** 1459,1465 ****
   * infinite recursion.
   */
  static List *
! RewriteQuery(Query *parsetree, List *rewrite_events)
  {
  	CmdType		event = parsetree->commandType;
  	bool		instead = false;
--- 1584,1591 ----
   * infinite recursion.
   */
  static List *
! RewriteQuery(Query *parsetree, List *rewrite_events, 
! 			 view_update_event *view_event)
  {
  	CmdType		event = parsetree->commandType;
  	bool		instead = false;
***************
*** 1550,1555 ****
--- 1676,1682 ----
  										result_relation,
  										event,
  										locks,
+ 										view_event,
  										&instead,
  										&qual_product);
  
***************
*** 1583,1589 ****
  					Query	   *pt = (Query *) lfirst(n);
  					List	   *newstuff;
  
! 					newstuff = RewriteQuery(pt, rewrite_events);
  					rewritten = list_concat(rewritten, newstuff);
  				}
  
--- 1710,1716 ----
  					Query	   *pt = (Query *) lfirst(n);
  					List	   *newstuff;
  
! 					newstuff = RewriteQuery(pt, rewrite_events, view_event);
  					rewritten = list_concat(rewritten, newstuff);
  				}
  
***************
*** 1646,1658 ****
  	CmdType		origCmdType;
  	bool		foundOriginalQuery;
  	Query	   *lastInstead;
  
  	/*
  	 * Step 1
  	 *
  	 * Apply all non-SELECT rules possibly getting 0 or many queries
  	 */
! 	querylist = RewriteQuery(parsetree, NIL);
  
  	/*
  	 * Step 2
--- 1773,1789 ----
  	CmdType		origCmdType;
  	bool		foundOriginalQuery;
  	Query	   *lastInstead;
+ 	view_update_event v_event;
  
  	/*
  	 * Step 1
  	 *
  	 * Apply all non-SELECT rules possibly getting 0 or many queries
  	 */
! 	v_event.viewUpdate      = false;
! 	v_event.needCheckOption = false;
! 	v_event.checkMode       = NO_OPTION_EXPLICIT;
! 	querylist = RewriteQuery(parsetree, NIL, &v_event);
  
  	/*
  	 * Step 2
Index: src/backend/rewrite/rewriteRemove.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v
retrieving revision 1.65
diff -c -r1.65 rewriteRemove.c
*** src/backend/rewrite/rewriteRemove.c	16 Jun 2006 20:23:44 -0000	1.65
--- src/backend/rewrite/rewriteRemove.c	30 Aug 2006 07:47:34 -0000
***************
*** 89,94 ****
--- 89,146 ----
  	performDeletion(&object, behavior);
  }
  
+ /*
+  * deleteImplicitRulesOnEvent
+  * 
+  * This will delete implicit rules, if any exists, on the event in the
+  * relation.
+  * You can use exceptOid to exclude a specific implicit
+  * rule from deletion, use InvalidOid if you want to
+  * safely delete all implicit rules.
+  */
+ void 
+ deleteImplicitRulesOnEvent(Relation rel, CmdType event_type,
+ 						   Oid exceptOid)
+ {
+ 	RuleLock *rulelocks = rel->rd_rules;
+ 	int nlocks;
+ 	int i;
+ 
+ 	/*
+ 	 * Select rules are implicit (are they marked as implicit??) 
+ 	 * but we don't want to delete them
+ 	 */
+ 	if (event_type == CMD_SELECT)
+ 		return;
+ 
+ 	/*
+ 	 * If there are no rules on the relation we waste no more time
+ 	 */
+ 	if (rulelocks == NULL)
+ 		return;
+ 
+ 	nlocks = rulelocks->numLocks;
+ 
+ 	/*
+ 	 * Look at all rules looking for the ones that are on the event and are
+ 	 * implicit
+ 	 */
+ 	for (i = 0; i < nlocks; i++)
+ 	{
+ 		RewriteRule *oneLock = rulelocks->rules[i];		
+ 		
+ 		if ((oneLock->event == event_type)
+ 			&& (oneLock->ev_kind != NO_OPTION_EXPLICIT)
+ 			&& (oneLock->ruleId != exceptOid))
+ 		{
+ 			RemoveRewriteRuleById(oneLock->ruleId);
+ 			elog(DEBUG1, "removing implicit rule with oid %d\n", 
+ 				 oneLock->ruleId);
+ 			deleteDependencyRecordsFor(RewriteRelationId, oneLock->ruleId);
+ 		}
+ 	}
+ }
+ 
  
  /*
   * Guts of rule deletion.
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.267
diff -c -r1.267 utility.c
*** src/backend/tcop/utility.c	25 Aug 2006 04:06:53 -0000	1.267
--- src/backend/tcop/utility.c	30 Aug 2006 07:47:35 -0000
***************
*** 20,25 ****
--- 20,26 ----
  #include "access/xact.h"
  #include "catalog/catalog.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_rewrite.h"
  #include "catalog/toasting.h"
  #include "commands/alter.h"
  #include "commands/async.h"
***************
*** 764,771 ****
  		case T_ViewStmt:		/* CREATE VIEW */
  			{
  				ViewStmt   *stmt = (ViewStmt *) parsetree;
  
! 				DefineView(stmt->view, stmt->query, stmt->replace);
  			}
  			break;
  
--- 765,787 ----
  		case T_ViewStmt:		/* CREATE VIEW */
  			{
  				ViewStmt   *stmt = (ViewStmt *) parsetree;
+ 				bool		checkOption = false;
+ 				bool		cascade = false;
+ 				ListCell   *cell;
  
! 				if (list_length(stmt->options) > 0)
! 					checkOption = true;
! 
! 				foreach(cell, stmt->options)
! 				{
! 					Value *val = (Value *) lfirst(cell);
! 
! 					if (strncmp(strVal(val), "cascade", strlen("cascade")) == 0)
! 						cascade = true;
! 				}
! 
! 				DefineView(stmt->view, stmt->query, stmt->replace, 
! 						   checkOption, cascade);
  			}
  			break;
  
***************
*** 807,813 ****
  			break;
  
  		case T_RuleStmt:		/* CREATE RULE */
! 			DefineQueryRewrite((RuleStmt *) parsetree);
  			break;
  
  		case T_CreateSeqStmt:
--- 823,829 ----
  			break;
  
  		case T_RuleStmt:		/* CREATE RULE */
! 			DefineQueryRewrite((RuleStmt *) parsetree, NO_OPTION_EXPLICIT);
  			break;
  
  		case T_CreateSeqStmt:
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.232
diff -c -r1.232 ruleutils.c
*** src/backend/utils/adt/ruleutils.c	21 Aug 2006 00:57:25 -0000	1.232
--- src/backend/utils/adt/ruleutils.c	30 Aug 2006 07:47:41 -0000
***************
*** 18,23 ****
--- 18,24 ----
  #include "catalog/pg_depend.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_rewrite.h"
  #include "catalog/pg_trigger.h"
  #include "executor/spi.h"
  #include "funcapi.h"
***************
*** 1683,1688 ****
--- 1684,1690 ----
  	Oid			ev_class;
  	int2		ev_attr;
  	bool		is_instead;
+ 	char        ev_kind;
  	char	   *ev_qual;
  	char	   *ev_action;
  	List	   *actions = NIL;
***************
*** 1705,1710 ****
--- 1707,1715 ----
  	fno = SPI_fnumber(rulettc, "is_instead");
  	is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
  
+ 	fno = SPI_fnumber(rulettc, "ev_kind");
+ 	ev_kind = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ 
  	fno = SPI_fnumber(rulettc, "ev_qual");
  	ev_qual = SPI_getvalue(ruletup, rulettc, fno);
  
***************
*** 1732,1737 ****
--- 1737,1761 ----
  
  	get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
  				  prettyFlags, 0);
+ 
+ 	/*
+ 	 * Support for updatable views: append the check option if
+ 	 * required. If any pretty print flags is enabled, we need
+ 	 * to do a linebreak before.
+ 	 */
+ 	if (ev_kind != NO_OPTION_EXPLICIT || ev_kind != NO_OPTION_IMPLICIT)
+ 	{
+ 		if (prettyFlags & PRETTYFLAG_INDENT)
+ 			appendStringInfo(buf, "\n");
+ 
+ 		appendStringInfoSpaces(buf, 1);
+ 
+ 		if (ev_kind == LOCAL_OPTION_IMPLICIT)
+ 			appendStringInfo(buf, " WITH LOCAL CHECK OPTION");
+ 		else if (ev_kind == CASCADED_OPTION_IMPLICIT)
+ 			appendStringInfo(buf, " WITH CASCADED CHECK OPTION");
+ 	}
+ 
  	appendStringInfo(buf, ";");
  
  	heap_close(ev_relation, AccessShareLock);
Index: src/backend/utils/cache/relcache.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/relcache.c,v
retrieving revision 1.247
diff -c -r1.247 relcache.c
*** src/backend/utils/cache/relcache.c	31 Jul 2006 20:09:05 -0000	1.247
--- src/backend/utils/cache/relcache.c	30 Aug 2006 07:47:48 -0000
***************
*** 646,651 ****
--- 646,652 ----
  		rule->event = rewrite_form->ev_type - '0';
  		rule->attrno = rewrite_form->ev_attr;
  		rule->isInstead = rewrite_form->is_instead;
+ 		rule->ev_kind = rewrite_form->ev_kind;
  
  		/*
  		 * Must use heap_getattr to fetch ev_action and ev_qual.  Also,
***************
*** 748,753 ****
--- 749,756 ----
  				return false;
  			if (!equal(rule1->actions, rule2->actions))
  				return false;
+ 			if(rule1->ev_kind != rule2->ev_kind)
+ 				return false;
  		}
  	}
  	else if (rlock2 != NULL)
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.447
diff -c -r1.447 pg_dump.c
*** src/bin/pg_dump/pg_dump.c	21 Aug 2006 00:57:25 -0000	1.447
--- src/bin/pg_dump/pg_dump.c	30 Aug 2006 07:47:52 -0000
***************
*** 51,56 ****
--- 51,57 ----
  #include "catalog/pg_proc.h"
  #include "catalog/pg_trigger.h"
  #include "catalog/pg_type.h"
+ #include "catalog/pg_rewrite.h"
  #include "commands/sequence.h"
  #include "libpq/libpq-fs.h"
  #include "mb/pg_wchar.h"
***************
*** 3658,3663 ****
--- 3659,3665 ----
  	int			i_ruletable;
  	int			i_ev_type;
  	int			i_is_instead;
+ 	int			i_ev_kind;
  
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
***************
*** 3666,3672 ****
  	{
  		appendPQExpBuffer(query, "SELECT "
  						  "tableoid, oid, rulename, "
! 						  "ev_class as ruletable, ev_type, is_instead "
  						  "FROM pg_rewrite "
  						  "ORDER BY oid");
  	}
--- 3668,3675 ----
  	{
  		appendPQExpBuffer(query, "SELECT "
  						  "tableoid, oid, rulename, "
! 						  "ev_class as ruletable, ev_type, is_instead, "
! 						  "ev_kind "
  						  "FROM pg_rewrite "
  						  "ORDER BY oid");
  	}
***************
*** 3675,3681 ****
  		appendPQExpBuffer(query, "SELECT "
  						  "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
  						  "oid, rulename, "
! 						  "ev_class as ruletable, ev_type, is_instead "
  						  "FROM pg_rewrite "
  						  "ORDER BY oid");
  	}
--- 3678,3685 ----
  		appendPQExpBuffer(query, "SELECT "
  						  "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
  						  "oid, rulename, "
! 						  "ev_class as ruletable, ev_type, is_instead, "
! 						  "ev_kind "
  						  "FROM pg_rewrite "
  						  "ORDER BY oid");
  	}
***************
*** 3695,3700 ****
--- 3699,3705 ----
  	i_ruletable = PQfnumber(res, "ruletable");
  	i_ev_type = PQfnumber(res, "ev_type");
  	i_is_instead = PQfnumber(res, "is_instead");
+ 	i_ev_kind = PQfnumber(res, "ev_kind");
  
  	for (i = 0; i < ntups; i++)
  	{
***************
*** 3718,3739 ****
  		ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
  		ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
  		ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
  		if (ruleinfo[i].ruletable)
  		{
  			/*
! 			 * If the table is a view, force its ON SELECT rule to be sorted
! 			 * before the view itself --- this ensures that any dependencies
! 			 * for the rule affect the table's positioning. Other rules are
! 			 * forced to appear after their table.
  			 */
! 			if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
! 				ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
! 			{
! 				addObjectDependency(&ruleinfo[i].ruletable->dobj,
! 									ruleinfo[i].dobj.dumpId);
! 				/* We'll merge the rule into CREATE VIEW, if possible */
! 				ruleinfo[i].separate = false;
! 			}
  			else
  			{
  				addObjectDependency(&ruleinfo[i].dobj,
--- 3723,3757 ----
  		ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
  		ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
  		ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
+ 		ruleinfo[i].ev_kind = *(PQgetvalue(res, i, i_ev_kind));
  		if (ruleinfo[i].ruletable)
  		{
  			/*
! 			 * If the table is a view, force its ON SELECT rule to be
! 			 * sorted before the view itself --- this ensures that any
! 			 * dependencies for the rule affect the table's positioning.
! 			 * Other rules are forced to appear after their table.
! 			 *
! 			 * Do the same for implicit rules (for updateable views support).
  			 */
! 			if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW) 
! 				if (ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
! 				{
! 					addObjectDependency(&ruleinfo[i].ruletable->dobj,
! 										ruleinfo[i].dobj.dumpId);
! 					/* We'll merge the rule into CREATE VIEW, if possible */
! 					ruleinfo[i].separate = false;
! 				}
! 				else
! 					if (ruleinfo[i].ev_kind != NO_OPTION_EXPLICIT)
! 					{
! 						addObjectDependency(&ruleinfo[i].ruletable->dobj,
! 											ruleinfo[i].dobj.dumpId);
! 						/* We'll merge the rule into CREATE VIEW, if possible */
! 						ruleinfo[i].separate = false;
! 					}
! 					else
! 						ruleinfo[i].separate = true;
  			else
  			{
  				addObjectDependency(&ruleinfo[i].dobj,
Index: src/bin/pg_dump/pg_dump.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dump.h,v
retrieving revision 1.129
diff -c -r1.129 pg_dump.h
*** src/bin/pg_dump/pg_dump.h	21 Aug 2006 00:57:25 -0000	1.129
--- src/bin/pg_dump/pg_dump.h	30 Aug 2006 07:47:53 -0000
***************
*** 260,267 ****
  	TableInfo  *ruletable;		/* link to table the rule is for */
  	char		ev_type;
  	bool		is_instead;
  	bool		separate;		/* TRUE if must dump as separate item */
! 	/* separate is always true for non-ON SELECT rules */
  } RuleInfo;
  
  typedef struct _triggerInfo
--- 260,271 ----
  	TableInfo  *ruletable;		/* link to table the rule is for */
  	char		ev_type;
  	bool		is_instead;
+ 	char		ev_kind;
  	bool		separate;		/* TRUE if must dump as separate item */
! 	/* 
! 	 * separate is true for non-ON SELECT rules and 
! 	 * for implicit rules (for updateable views support) 
! 	 */
  } RuleInfo;
  
  typedef struct _triggerInfo
Index: src/bin/pg_dump/pg_dump_sort.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dump_sort.c,v
retrieving revision 1.15
diff -c -r1.15 pg_dump_sort.c
*** src/bin/pg_dump/pg_dump_sort.c	14 Jul 2006 14:52:26 -0000	1.15
--- src/bin/pg_dump/pg_dump_sort.c	30 Aug 2006 07:47:55 -0000
***************
*** 816,821 ****
--- 816,862 ----
  		}
  	}
  
+ 	/* View and its implicit rule */
+ 	if (nLoop == 2 &&
+ 		loop[0]->objType == DO_TABLE &&
+ 		loop[1]->objType == DO_RULE &&
+ 		((RuleInfo *) loop[1])->ev_kind != 'e' &&
+ 		((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
+ 	{
+ 		repairViewRuleLoop(loop[0], loop[1]);
+ 		return;
+ 	}
+ 	if (nLoop == 2 &&
+ 		loop[1]->objType == DO_TABLE &&
+ 		loop[0]->objType == DO_RULE &&
+ 		((RuleInfo *) loop[0])->ev_kind != 'e' &&
+ 		((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
+ 	{
+ 		repairViewRuleLoop(loop[1], loop[0]);
+ 		return;
+ 	}
+ 
+ 	/* Indirect loop involving view and implicit rule */
+ 	if (nLoop > 2)
+ 	{
+ 		for (i = 0; i < nLoop; i++)
+ 		{
+ 			if (loop[i]->objType == DO_TABLE)
+ 			{
+ 				for (j = 0; j < nLoop; j++)
+ 				{
+ 					if (loop[j]->objType == DO_RULE &&
+ 						((RuleInfo *) loop[j])->ev_kind != 'e' &&
+ 						((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
+ 					{
+ 						repairViewRuleMultiLoop(loop[i], loop[j]);
+ 						return;
+ 					}
+ 				}
+ 			}
+ 		}
+ 	}
+ 
  	/* Table and CHECK constraint */
  	if (nLoop == 2 &&
  		loop[0]->objType == DO_TABLE &&
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.422
diff -c -r1.422 pg_proc.h
*** src/include/catalog/pg_proc.h	19 Aug 2006 01:36:33 -0000	1.422
--- src/include/catalog/pg_proc.h	30 Aug 2006 07:47:58 -0000
***************
*** 3845,3850 ****
--- 3845,3851 ----
  DESCR("convert int4 to boolean");
  DATA(insert OID = 2558 ( int4				   PGNSP PGUID 12 f f t f i 1  23 "16" _null_ _null_ _null_ bool_int4 - _null_ ));
  DESCR("convert boolean to int4");
+ /* internal function required for view update rules */
  DATA(insert OID = 2559 ( lastval			   PGNSP PGUID 12 f f t f v 0 20 "" _null_ _null_ _null_	lastval - _null_ ));
  DESCR("current value from last used sequence");
  
***************
*** 3898,3903 ****
--- 3899,3908 ----
  DATA(insert OID = 2592 (  gist_circle_compress	PGNSP PGUID 12 f f t f i 1 2281 "2281" _null_ _null_ _null_ gist_circle_compress - _null_ ));
  DESCR("GiST support");
  
+ /* functions for view update facility */
+ DATA(insert OID = 2570 ( pg_view_update_error       PGNSP PGUID 12 f f f f i 1 16 "16" _null_ _null_ _null_ pg_view_update_error - _null_));
+ DESCR("evaluates boolean input for view update check option");
+ 
  /* GIN */
  DATA(insert OID = 2730 (  gingettuple	   PGNSP PGUID 12 f f t f v 2 16 "2281 2281" _null_ _null_ _null_  gingettuple - _null_ ));
  DESCR("gin(internal)");
Index: src/include/catalog/pg_rewrite.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_rewrite.h,v
retrieving revision 1.26
diff -c -r1.26 pg_rewrite.h
*** src/include/catalog/pg_rewrite.h	5 Mar 2006 15:58:55 -0000	1.26
--- src/include/catalog/pg_rewrite.h	30 Aug 2006 07:47:58 -0000
***************
*** 43,48 ****
--- 43,49 ----
  	int2		ev_attr;
  	char		ev_type;
  	bool		is_instead;
+ 	char		ev_kind;
  
  	/* NB: remaining fields must be accessed via heap_getattr */
  	text		ev_qual;
***************
*** 60,72 ****
   *		compiler constants for pg_rewrite
   * ----------------
   */
! #define Natts_pg_rewrite				7
  #define Anum_pg_rewrite_rulename		1
  #define Anum_pg_rewrite_ev_class		2
  #define Anum_pg_rewrite_ev_attr			3
  #define Anum_pg_rewrite_ev_type			4
  #define Anum_pg_rewrite_is_instead		5
! #define Anum_pg_rewrite_ev_qual			6
! #define Anum_pg_rewrite_ev_action		7
  
  #endif   /* PG_REWRITE_H */
--- 61,84 ----
   *		compiler constants for pg_rewrite
   * ----------------
   */
! #define Natts_pg_rewrite				8
  #define Anum_pg_rewrite_rulename		1
  #define Anum_pg_rewrite_ev_class		2
  #define Anum_pg_rewrite_ev_attr			3
  #define Anum_pg_rewrite_ev_type			4
  #define Anum_pg_rewrite_is_instead		5
! #define Anum_pg_rewrite_ev_kind			6
! #define Anum_pg_rewrite_ev_qual			7
! #define Anum_pg_rewrite_ev_action		8
! 
! /*
!  * Possible values for ev_kind 
!  */
! #define LOCAL_OPTION_IMPLICIT    'l' /* WITH LOCAL CHECK OPTION */
! #define CASCADED_OPTION_IMPLICIT 'c' /* WITH CASCADED CHECK OPTION */
! #define NO_OPTION_IMPLICIT       'n' /* no check option specified */
! #define NO_OPTION_NOTHING_RULE   'r' /* identifier for implicit
! 										INSTEAD NOTHING	RULE */
! #define NO_OPTION_EXPLICIT       'e' /* rule was created by user */
  
  #endif   /* PG_REWRITE_H */
Index: src/include/commands/view.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/view.h,v
retrieving revision 1.23
diff -c -r1.23 view.h
*** src/include/commands/view.h	5 Mar 2006 15:58:55 -0000	1.23
--- src/include/commands/view.h	30 Aug 2006 07:47:58 -0000
***************
*** 16,22 ****
  
  #include "nodes/parsenodes.h"
  
! extern void DefineView(RangeVar *view, Query *view_parse, bool replace);
  extern void RemoveView(const RangeVar *view, DropBehavior behavior);
  
  #endif   /* VIEW_H */
--- 16,24 ----
  
  #include "nodes/parsenodes.h"
  
! extern void DefineView(RangeVar *view, Query *view_parse, bool replace, 
! 					   bool checkOption, bool cascade);
! 
  extern void RemoveView(const RangeVar *view, DropBehavior behavior);
  
  #endif   /* VIEW_H */
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.325
diff -c -r1.325 parsenodes.h
*** src/include/nodes/parsenodes.h	25 Aug 2006 04:06:56 -0000	1.325
--- src/include/nodes/parsenodes.h	30 Aug 2006 07:47:59 -0000
***************
*** 1673,1678 ****
--- 1673,1679 ----
  	List	   *aliases;		/* target column names */
  	Query	   *query;			/* the SQL statement */
  	bool		replace;		/* replace an existing view? */
+ 	List	   *options;        /* view check options, NIL means no check */
  } ViewStmt;
  
  /* ----------------------
Index: src/include/nodes/relation.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/relation.h,v
retrieving revision 1.126
diff -c -r1.126 relation.h
*** src/include/nodes/relation.h	1 Jul 2006 18:38:33 -0000	1.126
--- src/include/nodes/relation.h	30 Aug 2006 07:48:00 -0000
***************
*** 260,266 ****
  
  	/* information about a base rel (not set for join rels!) */
  	Index		relid;
! 	RTEKind		rtekind;		/* RELATION, SUBQUERY, or FUNCTION */
  	AttrNumber	min_attr;		/* smallest attrno of rel (often <0) */
  	AttrNumber	max_attr;		/* largest attrno of rel */
  	Relids	   *attr_needed;	/* array indexed [min_attr .. max_attr] */
--- 260,266 ----
  
  	/* information about a base rel (not set for join rels!) */
  	Index		relid;
! 	RTEKind		rtekind;		/* see parsenodes.h */
  	AttrNumber	min_attr;		/* smallest attrno of rel (often <0) */
  	AttrNumber	max_attr;		/* largest attrno of rel */
  	Relids	   *attr_needed;	/* array indexed [min_attr .. max_attr] */
Index: src/include/rewrite/prs2lock.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/rewrite/prs2lock.h,v
retrieving revision 1.21
diff -c -r1.21 prs2lock.h
*** src/include/rewrite/prs2lock.h	5 Mar 2006 15:58:58 -0000	1.21
--- src/include/rewrite/prs2lock.h	30 Aug 2006 07:48:01 -0000
***************
*** 29,34 ****
--- 29,35 ----
  	Node	   *qual;
  	List	   *actions;
  	bool		isInstead;
+ 	char        ev_kind;
  } RewriteRule;
  
  /*
Index: src/include/rewrite/rewriteDefine.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/rewrite/rewriteDefine.h,v
retrieving revision 1.21
diff -c -r1.21 rewriteDefine.h
*** src/include/rewrite/rewriteDefine.h	5 Mar 2006 15:58:58 -0000	1.21
--- src/include/rewrite/rewriteDefine.h	30 Aug 2006 07:48:01 -0000
***************
*** 16,22 ****
  
  #include "nodes/parsenodes.h"
  
! extern void DefineQueryRewrite(RuleStmt *args);
  
  extern void RenameRewriteRule(Oid owningRel, const char *oldName,
  				  const char *newName);
--- 16,23 ----
  
  #include "nodes/parsenodes.h"
  
! extern void DefineQueryRewrite(RuleStmt *args,
! 							   char     ev_kind);
  
  extern void RenameRewriteRule(Oid owningRel, const char *oldName,
  				  const char *newName);
Index: src/include/rewrite/rewriteRemove.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/rewrite/rewriteRemove.h,v
retrieving revision 1.22
diff -c -r1.22 rewriteRemove.h
*** src/include/rewrite/rewriteRemove.h	16 Jun 2006 20:23:45 -0000	1.22
--- src/include/rewrite/rewriteRemove.h	30 Aug 2006 07:48:01 -0000
***************
*** 20,24 ****
--- 20,26 ----
  extern void RemoveRewriteRule(Oid owningRel, const char *ruleName,
  				  DropBehavior behavior, bool missing_ok);
  extern void RemoveRewriteRuleById(Oid ruleOid);
+ extern void deleteImplicitRulesOnEvent(Relation rel, CmdType event_type, 
+                                        Oid exceptOid);
  
  #endif   /* REWRITEREMOVE_H */
Index: src/include/rewrite/rewriteSupport.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/rewrite/rewriteSupport.h,v
retrieving revision 1.28
diff -c -r1.28 rewriteSupport.h
*** src/include/rewrite/rewriteSupport.h	5 Mar 2006 15:58:58 -0000	1.28
--- src/include/rewrite/rewriteSupport.h	30 Aug 2006 07:48:01 -0000
***************
*** 17,22 ****
--- 17,33 ----
  /* The ON SELECT rule of a view is always named this: */
  #define ViewSelectRuleName	"_RETURN"
  
+ /*------------------------------------------------------------------------------
+  * some names to be used for implicit view update rules
+  *------------------------------------------------------------------------------
+  */
+ #define INSERTRULENAME "_INSERT"
+ #define DELETERULENAME "_DELETE"
+ #define UPDATERULENAME "_UPDATE"
+ #define NOTHING_INSERTRULENAME "_NOTHING_INSERT"
+ #define NOTHING_UPDATERULENAME "_NOTHING_UPDATE"
+ #define NOTHING_DELETERULENAME "_NOTHING_DELETE"
+ 
  extern bool IsDefinedRewriteRule(Oid owningRel, const char *ruleName);
  
  extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
